import requests
import json
import base64
import hmac
import hashlib
import time
import os
from ..exceptions import PlatformAPIException, PlatformRequestException, PlatformNotSupportSymbolException, PlatformClientException
from ..restapibase import RestAPIBase
from .symbols import symbols


class BitfinexRESTAPI(RestAPIBase):
    """docstring for BitfinexRESTAPI"""

    def __init__(self, api_key, secret_key, isdebug):
        self.api_key = api_key
        self.api_secret = secret_key
        self.isdebug = isdebug
        self.url = 'https://api.bitfinex.com'

    def _debug(self, result):
        if self.isdebug:
            print(result)

    def _get_auth(self, endpoint, data):
        nonce = str(int(time.time() * 1e6))
        data.update({'request': endpoint, 'nonce': nonce})

        payload = base64.b64encode(json.dumps(data).encode('utf-8'))
        secret = self.api_secret.encode('utf-8')
        signature = hmac.new(secret, payload, hashlib.sha384).hexdigest()

        headers = {'x-bfx-apikey': self.api_key,
                   'x-bfx-payload': payload,
                   'x-bfx-signature': signature}
        return headers

    def _get(self, endpoint, params={}):
        url = self.url + endpoint
        self._debug(url)

        response = requests.get(url, params)

        rescode = response.status_code
        errmsg = 'StatusCode: GET %s \nURL:%s \nParams: %s \nResponse: %s' % (
            response.status_code, url, str(params), response.text)
        response = response.json()

        if response or rescode == 200:
            if rescode == 200:
                return response
            elif rescode == 400:
                raise PlatformAPIException(errmsg)
        else:
            raise PlatformRequestException(errmsg)

    def _post(self, endpoint, data={}):
        url = self.url + endpoint
        self._debug(url)
        headers = self._get_auth(endpoint, data)
        response = requests.post(url, headers=headers, verify=True)
        self._debug(response)

        rescode = response.status_code
        errmsg = 'StatusCode: POST %s \nURL:%s \nData: %s \nResponse: %s' % (
            response.status_code, url, str(data), response.text)
        response = response.json()

        if response or rescode == 200:
            if rescode == 200:
                return response
            elif rescode == 400:
                raise PlatformAPIException(errmsg)
        else:
            raise PlatformRequestException(errmsg)

    # EndPoints
    def _symbols(self):
        url = '/v1/symbols'

        resjson = self._get(url)
        self._debug('symbols: \n' + json.dumps(resjson, indent=2))

        result = []
        for res in resjson:
            result.append(res)
        sw = open(os.path.dirname(
            os.path.realpath(__file__)) + '/symbols.py', 'w')
        sw.write('symbols = ' + str(result))
        sw.close()
        self._debug('symbols: \n' + str(result))

        return result

    def _order(self, symbol, side, ordertype, amount, price):
        url = '/v1/order/new'
        data = {
            'symbol': symbol,
            'side': side,
            'amount': str(amount),
            'price': str(price),
            'exchange': 'bitfinex',
            'type': ordertype,
        }

        result = self._post(url, data)
        return result

    # Public method
    def get_currency(self, currency):
        if currency.lower() == 'dash':
            return 'dsh'
        else:
            return currency.lower()

    def get_symbol(self, commodity, base):
        commodity = commodity.lower()

        if commodity == 'dash':
            commodity = 'dsh'
        elif commodity == 'iota':
            commodity = 'iot'
        elif commodity == 'qtum':
            commodity = 'qtm'
        elif commodity == 'data':
            commodity = 'dat'

        result = commodity.lower() + base.lower()

        if not (result in symbols):
            errmsg = 'Not supported: %s' % result
            raise PlatformNotSupportSymbolException(errmsg)

        return result

    def get_ticker(self, symbol):
        url = '/v1/pubticker/' + symbol

        result = self._get(url)
        self._debug('ticker: \n' + json.dumps(result, indent=2))
        return result

    def get_depth(self, symbol):
        url = '/v1/book/' + symbol

        result = self._get(url)
        self._debug('ticker: \n' + json.dumps(result, indent=2))
        return result

    # NotImplementedError
    def get_positions(self):
        url = '/v1/positions'

        resjson = self._post(url)
        result = {}
        for balance in resjson:
            result[balance['symbol']] = balance['pl']

        self._debug('get_positions: \n' + json.dumps(result, indent=2))
        return result

    def get_account(self):
        raise NotImplementedError()

    def get_balances(self, type='trade'):
        url = '/v1/balances'

        resjson = self._post(url)
        result = {}

        if type=='trade':
            for balance in resjson:
                if balance['type'] == 'exchange':
                    result[balance['currency']] = balance['available']
        elif type=='margin':
            for balance in resjson:
                if balance['type'] == 'trading':
                    if balance['currency'] in result:
                        result[balance['currency']] += float(balance['amount'])
                    else:
                        result[balance['currency']] = float(balance['amount'])

        self._debug('get_balances: \n' + json.dumps(result, indent=2))
        return result

    def limit_buy(self, symbol, amount, price):
        resjson = self._order(symbol, 'buy', 'exchange limit', amount, price)
        result = {"id": resjson["order_id"]}
        self._debug('limit_buy: \n' + json.dumps(result, indent=2))
        return result

    def limit_sell(self, symbol, amount, price):
        resjson = self._order(symbol, 'sell', 'exchange limit', amount, price)
        result = {"id": resjson["order_id"]}
        self._debug('limit_sell: \n' + json.dumps(result, indent=2))
        return result

    def market_buy(self, symbol, amount, price):
        resjson = self._order(symbol, 'buy', 'exchange market', amount, price)
        result = {"id": resjson["order_id"]}

        self._debug('market_buy: \n' + json.dumps(result, indent=2))
        return result

    def market_sell(self, symbol, amount, price):
        resjson = self._order(symbol, 'sell', 'exchange market', amount, price)
        result = {"id": resjson["order_id"]}

        self._debug('market_sell: \n' + json.dumps(result, indent=2))
        return result

    def get_order(self, order_id):
        url = '/v1/order/status'
        data = {
            'order_id': order_id,
        }

        result = self._post(url, data)
        self._debug('orderid[ ' + str(order_id) + ' ]: ' +
                    json.dumps(result, indent=2))
        return result

    # NotImplementedError
    def get_all_orders(self):
        raise NotImplementedError()

    def get_open_orders(self):
        url = '/v1/orders'

        result = self._post(url)
        self._debug('orders: ' + json.dumps(result, indent=2))
        return result

    def cancel_order(self, order_id):
        url = '/v1/order/cancel'
        data = {
            'order_id': order_id,
        }

        result = self._post(url, data)
        self._debug(
            'orderid cancel[ ' + str(order_id) + ' ]: ' + json.dumps(result, indent=2))
        return result

    def cancel_all_orders(self):
        url = '/v1/order/cancel/all'

        resjson = self._post(url)
        result = False
        if "All" in resjson['result'] or resjson['result'] == 'None to cancel':
            result = True
        self._debug('cancel_all_orders: ' + json.dumps(resjson, indent=2))
        return resjson

    def withdraw(self, currency, amount, address):
        url = '/v1/withdrawls'
        data = {
            "withdraw_type": currency,
            "walletselected": "exchange",
            "amount": amount,
            "address": address,
        }

        result = self._post(url, data)
        self._debug('transfer: \n' + json.dumps(result, indent=2))
        return result
